package com.tiancheng.trade.settlement.service.settlement.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tiancheng.trade.commom.core.data.PageInfo;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.settlement.bo.*;
import com.tiancheng.trade.settlement.enums.OrderSourceEnum;
import com.tiancheng.trade.settlement.enums.RevenueStatusEnum;
import com.tiancheng.trade.settlement.enums.RevenueTypeEnum;
import com.tiancheng.trade.settlement.enums.SystemSourceEnum;
import com.tiancheng.trade.settlement.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.settlement.mapper.settlement.SRevenueDetailMapper;
import com.tiancheng.trade.settlement.model.order.Orders;
import com.tiancheng.trade.settlement.model.order.SubOrder;
import com.tiancheng.trade.settlement.model.settlement.SRevenueDetail;
import com.tiancheng.trade.settlement.service.merchant.IMerchantService;
import com.tiancheng.trade.settlement.service.order.IOrderService;
import com.tiancheng.trade.settlement.service.order.ISubOrderService;
import com.tiancheng.trade.settlement.service.settlement.ISRevenueDetailService;
import com.tiancheng.trade.settlement.util.*;
import com.tiancheng.trade.settlement.vo.settlement.admin.BaseRevenueQueryVo;
import com.tiancheng.trade.settlement.vo.settlement.api.NcCloudReqVO;
import com.tiancheng.trade.settlement.vo.settlement.api.NcCloudResVO;
import com.tiancheng.trade.settlement.vo.settlement.api.TallyOrderServiceSuccessVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Auther: Likailun
 * @Date: 11:13 2021/4/25
 * @Description: 收入明细service
 */
@Slf4j
@Service
public class SRevenueDetailServiceImpl extends ServiceImpl<SRevenueDetailMapper, SRevenueDetail> implements ISRevenueDetailService {

    @Resource
    private IOrderService orderService;
    @Resource
    private ISubOrderService subOrderService;
    @Resource
    private IMerchantService merchantService;
    @Resource
    private IdGenerateUtil idGenerateUtil;

    private final List<String> orgCodes= Arrays.asList("CCC63EF4D782A2259461D4B8EE51FCA6", "899C97159DB7B967A961ECE8EAA355A3");

    @Override
    public void subOrderSuccess(TallyOrderServiceSuccessVO bo) {
        BusinessErrorInfoEnum.MESSAGE_ARGS_ERROR.assertIsTrue(null != bo && !StringUtils.isEmpty(bo.getOrderId())
                && !CollectionUtils.isEmpty(bo.getSubOrderIds()) && "SC".equals(bo.getSubOrderStatus()));
        //针对主订单加锁，防止重复推送的数据导致重复

        try (Lock lock = new Lock(Lock.LOCK_ORDER_SUCCESS, bo.getOrderId(), 5, 5)) {
            BusinessErrorInfoEnum.LOCK_TIMEOUT_ERROR.assertIsTrue(lock.getLockRes());
            Orders order = orderService.findByOrderId(bo.getOrderId());
            BusinessErrorInfoEnum.MESSAGE_NOT_EXIT_ORDER_ERROR.assertIsTrue(order != null && StringUtils.isNotEmpty(order.getOrderId()));
            List<SubOrder> subOrders = subOrderService.findByOrderIdAndSubOrderIds(order.getOrderId(), bo.getSubOrderIds());
            BusinessErrorInfoEnum.MESSAGE_NOT_EXIT_ORDER_ERROR.assertIsTrue(!CollectionUtils.isEmpty(subOrders));
            // 已统计过的子订单
            List<SRevenueDetail> exitSubOrders = this.findByOrderIdAndSubOrderIds(bo.getOrderId(), bo.getSubOrderIds());
            // 查询商户信息，可优化（缓存商户信息）
            List<MerchantQueryBo> merchantCods = merchantService.findByMerchantCods(subOrders.stream().map(SubOrder::getMerchantCode).collect(Collectors.toList()));
            BusinessErrorInfoEnum.MESSAGE_NOT_EXIT_ORDER_ERROR.assertIsTrue(!CollectionUtils.isEmpty(merchantCods));

            List<SRevenueDetail> revenueDetails = new ArrayList<>();
            for (SubOrder subOrder : subOrders) {
                boolean subOrderExit = false;
                if (!CollectionUtils.isEmpty(exitSubOrders)) {
                    subOrderExit = exitSubOrders.stream().anyMatch(s -> s.getSubOrderId().equals(subOrder.getSubOrderId()));
                }
                if (subOrderExit) {
                    log.info("子订单{}已统计过收入", subOrder.getSubOrderId());
                    continue;
                }

                SRevenueDetail revenueDetail = ObjectConvertUtil.convert(subOrder, SRevenueDetail.class).get();
                revenueDetail.setId(null);
                revenueDetail.setCreatedBy(null);
                revenueDetail.setLastUpdBy(null);
                revenueDetail.setLastUpdDt(null);
                revenueDetail.setCreatedDt(LocalDateTime.now());
                revenueDetail.setSubOrderCreateDt(subOrder.getCreatedDt());
                revenueDetail.setPayFlowId(order.getFlowId());
                revenueDetail.setSystemSource(order.getSystemSource());

                // 处理未统计过收入的订单
                // step1、查询商户、机构信息、获取商户的确认规则
                MerchantQueryBo merchantQueryBo = this.getMerchantRevenueType(merchantCods, subOrder.getMerchantCode());
                if (null == merchantQueryBo) {
                    // 无商户
                    log.error("子订单收入确认异常，订单号：{}，商户号：{}，异常：{}", subOrder.getSubOrderId(), subOrder.getMerchantCode(), RevenueStatusEnum.NO_MERCHANT.getDesc());
                    revenueDetail.setRevenueStatus(RevenueStatusEnum.NO_MERCHANT.getCode());
                    revenueDetails.add(revenueDetail);
                    continue;
                }
                revenueDetail.setOrgCode(merchantQueryBo.getOrganizationCode());
                revenueDetail.setOrgName(merchantQueryBo.getOrganizationName());
                if (StringUtils.isEmpty(merchantQueryBo.getRevenueType())) {
                    // 未配置收入确认类型
                    log.error("子订单收入确认异常，订单号：{}，商户号：{}，异常：{}", subOrder.getSubOrderId(), subOrder.getMerchantCode(), RevenueStatusEnum.NO_REVENUE_TYPE.getDesc());
                    revenueDetail.setRevenueStatus(RevenueStatusEnum.NO_REVENUE_TYPE.getCode());
                    revenueDetails.add(revenueDetail);
                    continue;
                }
                RevenueTypeEnum revenueTypeEnum = RevenueTypeEnum.getRevenueTypeEnum(merchantQueryBo.getRevenueType());
                if (null == revenueTypeEnum) {
                    // 未配置收入确认类型
                    log.error("子订单收入确认异常，订单号：{}，商户号：{}，异常：{}", subOrder.getSubOrderId(), subOrder.getMerchantCode(), RevenueStatusEnum.NOT_SUPPORT_REVENUE_TYPE.getDesc());
                    revenueDetail.setRevenueStatus(RevenueStatusEnum.NOT_SUPPORT_REVENUE_TYPE.getCode());
                    revenueDetails.add(revenueDetail);
                    continue;
                }

                revenueDetail.setRevenueType(merchantQueryBo.getRevenueType());
                revenueDetail.setPlatformRevenueScale(merchantQueryBo.getPlatformRevenueScale());
                revenueDetail.setPlatformRevenueAmount(merchantQueryBo.getPlatformRevenueAmount());
                // step2、计算商户收入
                revenueDetail.setRevenueAmount(this.getRevenueAmount(subOrder, merchantQueryBo));
                // step3、计算结果入库
                revenueDetails.add(revenueDetail);
            }
            if (!CollectionUtils.isEmpty(revenueDetails)) {
                this.saveBatch(revenueDetails);
            }
        }catch (Exception e){
            BusinessErrorInfoEnum.LOCK_TIMEOUT_ERROR.assertFail();
        }
    }

    @Override
    public List<SRevenueDetail> findByOrderIdAndSubOrderIds(String orderId, List<String> subOrderIds) {
        BusinessErrorInfoEnum.MESSAGE_ARGS_ERROR.assertIsTrue(!StringUtils.isEmpty(orderId)
                && !CollectionUtils.isEmpty(subOrderIds));
        QueryWrapper<SRevenueDetail> condition = new QueryWrapper<>();
        condition.eq("order_id", orderId);
        condition.in("sub_order_id", subOrderIds);
        condition.eq("revenue_status", RevenueStatusEnum.NORMAL.getCode());
        return this.getBaseMapper().selectList(condition);
    }

    @Override
    public List<SRevenueSummaryBO> revenueSummary(BaseRevenueQueryVo revenueQueryVo) {
        if (CollectionUtils.isEmpty(revenueQueryVo.getRevenueStatus())) {
            // 如果没有传入状态，则默认统计有效记录
            revenueQueryVo.setRevenueStatus(Collections.singletonList(RevenueStatusEnum.NORMAL.getCode()));
        }
        BaseRevenueQueryBO baseRevenueQueryBO = this.queryDateHandle(revenueQueryVo);
        List<SRevenueSummaryBO> list = this.getBaseMapper().getSRevenueSummaryGroupByRevenueType(baseRevenueQueryBO);
        if (!CollectionUtils.isEmpty(list)) {
            // 合计行
            SRevenueSummaryBO summation = new SRevenueSummaryBO();
            summation.setRevenueType(RevenueTypeEnum.SUMMATION.getRevenueType());
            summation.setRevenueTypeName(RevenueTypeEnum.getDesc(RevenueTypeEnum.SUMMATION.getRevenueType()));
            //合计收入确认-销售金额
            AtomicReference<Integer> summationSubOrderAmountTotal = new AtomicReference<>(0);
            //合计-收入确认-优惠金额
            AtomicReference<Integer> summationDiscountTotal = new AtomicReference<>(0);
            //合计-收入确认-结算金额
            AtomicReference<Integer> summationProductCostTotal = new AtomicReference<>(0);
            //合计-收入确认-收入金额
            AtomicReference<Integer> summationRevenueAmountTotal = new AtomicReference<>(0);
            //合计-收入确认-服务成功笔数
            AtomicReference<Integer> summationScOrderCount = new AtomicReference<>(0);

            list.forEach(item -> {
                item.setRevenueTypeName(RevenueTypeEnum.getDesc(item.getRevenueType()));
                summationSubOrderAmountTotal.updateAndGet(v -> v + (item.getSubOrderAmountTotal() == null ? 0 : item.getSubOrderAmountTotal()));
                summationDiscountTotal.updateAndGet(v -> v + (item.getDiscountTotal() == null ? 0 : item.getDiscountTotal()));
                summationProductCostTotal.updateAndGet(v -> v + (item.getProductCostTotal() == null ? 0 : item.getProductCostTotal()));
                summationScOrderCount.updateAndGet(v -> v + (item.getScOrderCount() == null ? 0 : item.getScOrderCount()));
                summationRevenueAmountTotal.updateAndGet(v -> v + (item.getRevenueAmountTotal() == null ? 0 : item.getRevenueAmountTotal()));
            });
            summation.setSubOrderAmountTotal(summationSubOrderAmountTotal.get());
            summation.setDiscountTotal(summationDiscountTotal.get());
            summation.setRevenueAmountTotal(summationRevenueAmountTotal.get());
            summation.setProductCostTotal(summationProductCostTotal.get());
            summation.setScOrderCount(summationScOrderCount.get());
            list.add(summation);
        }
        return list;
    }

    @Override
    public PageInfo<SRevenueDetailQueryResBo> revenueDetail(BaseRevenueQueryVo revenueQueryVo) {
        revenueQueryVo.buildStart();
        if (CollectionUtils.isEmpty(revenueQueryVo.getRevenueStatus())) {
            // 如果没有传入状态，则默认统计有效记录
            revenueQueryVo.setRevenueStatus(Collections.singletonList(RevenueStatusEnum.NORMAL.getCode()));
        }
        BaseRevenueQueryBO baseRevenueQueryBO = this.queryDateHandle(revenueQueryVo);
        Integer count = this.getBaseMapper().getSRevenueDetailGroupByProductCodeCount(baseRevenueQueryBO);
        List<SRevenueDetailQueryResBo> list = null;
        if (null != count && count > 0) {
            list = this.getBaseMapper().getSRevenueDetailGroupByProductCode(baseRevenueQueryBO);
            if (!CollectionUtils.isEmpty(list)) {
                list.forEach(item -> {
                    item.setSettleRange(DateTimeUtil.format(revenueQueryVo.getStartDate(),DateTimeUtil.YYYYMMDD_INTERVAL)+"至"
                            +DateTimeUtil.format(revenueQueryVo.getEndDate(),DateTimeUtil.YYYYMMDD_INTERVAL));
                    item.setRevenueTypeName(RevenueTypeEnum.getDesc(item.getRevenueType()));
                    item.setOrderSourceName(OrderSourceEnum.getDesc(item.getOrderSource()));
                    item.setSystemSource(SystemSourceEnum.getDesc(item.getSystemSource()));
                });
            }
        }
        return new PageInfo<SRevenueDetailQueryResBo>(list, new PageInfo.Pagination(revenueQueryVo.getCurrentPage(), revenueQueryVo.getPageSize(), count));
    }

    @Override
    public Result exportDetail(BaseRevenueQueryVo revenueQueryVo, HttpServletRequest request, HttpServletResponse response) throws IllegalAccessException, IOException {
        if (CollectionUtils.isEmpty(revenueQueryVo.getRevenueStatus())) {
            // 如果没有传入状态，则默认统计有效记录
            revenueQueryVo.setRevenueStatus(Collections.singletonList(RevenueStatusEnum.NORMAL.getCode()));
        }
        if (revenueQueryVo.getEndDate().until(revenueQueryVo.getStartDate(), ChronoUnit.DAYS) > 365) {
            return Result.fail("统计周期最长不能超过365天");
        }
        BaseRevenueQueryBO baseRevenueQueryBO = this.queryDateHandle(revenueQueryVo);
        baseRevenueQueryBO.buildStart();
        Integer count = this.getBaseMapper().getSRevenueDetailGroupByProductCodeCount(baseRevenueQueryBO);
        if (null != count && count > 0) {
            List<SRevenueDetailQueryResBo> list = this.getBaseMapper().getSRevenueDetailGroupByProductCode(baseRevenueQueryBO);
            if (!CollectionUtils.isEmpty(list)) {
                List<SRevenueDetailExportBO> revenueDetailExportBOS = new ArrayList<>();
                String startDateStr = DateTimeUtil.format(revenueQueryVo.getStartDate(), DateTimeUtil.YYYYMMDD_INTERVAL);
                String endDateStr = DateTimeUtil.format(revenueQueryVo.getEndDate(), DateTimeUtil.YYYYMMDD_INTERVAL);
                list.forEach(item -> {
                    SRevenueDetailExportBO sRevenueDetailExportBO = SRevenueDetailExportBO.build(item);
                    sRevenueDetailExportBO.setStatisticsCycle(startDateStr+"至"+ endDateStr);
                    sRevenueDetailExportBO.setSystemSource(SystemSourceEnum.getDesc(item.getSystemSource()));
                    revenueDetailExportBOS.add(sRevenueDetailExportBO);
                });
                String[] allTitleSummary = {"统计周期", "收入确认类型", "场景", "组织机构", "商户名称", "产品名称","销售金额","优惠金额","结算金额","服务成功笔数","收入","腾云应收（比例）","腾云应收（固定金额）","系统来源"};

                String fileName = String.format("%s至%s收入成本明细统计.xlsx", startDateStr, endDateStr);
                List<ExportBO> exportBoS = new ArrayList<>();
                ExportBO exportBoSummary = new ExportBO(fileName.replace(".xlsx", ""), null, allTitleSummary, revenueDetailExportBOS);
                exportBoS.add(exportBoSummary);
                Workbook workbook = ExcelUtil.buildExcelWorkBook(exportBoS);
                ExcelUtil.exportExcle(request, response, workbook, fileName);
                return Result.success();
            }
        }
        return Result.fail("未查询到收入确认记录");
    }

    @Override
    public Result exportSummary(BaseRevenueQueryVo revenueQueryVo, HttpServletRequest request, HttpServletResponse response) throws IllegalAccessException, IOException {
        List<SRevenueSummaryBO> summaryBOList = this.revenueSummary(revenueQueryVo);
        if (!CollectionUtils.isEmpty(summaryBOList)) {
            String startDateStr = DateTimeUtil.format(revenueQueryVo.getStartDate(), DateTimeUtil.YYYYMMDD_INTERVAL);
            String endDateStr = DateTimeUtil.format(revenueQueryVo.getEndDate(), DateTimeUtil.YYYYMMDD_INTERVAL);
            String fileName = String.format("%s至%s收入成本汇总统计.xlsx", startDateStr, endDateStr);
            List<ExportBO> exportBoS = new ArrayList<>();
            String[] allTitleSummary = {"收入确认类型", "销售金额", "优惠金额", "结算金额", "收入", "服务成功笔数"};

            List<SRevenueSummaryExportBO> collect = new ArrayList<>(summaryBOList.size());
            summaryBOList.forEach(s->collect.add(SRevenueSummaryExportBO.build(s)));
            ExportBO exportBoSummary = new ExportBO(fileName.replace(".xlsx", ""), null, allTitleSummary, collect);
            exportBoS.add(exportBoSummary);
            Workbook workbook = ExcelUtil.buildExcelWorkBook(exportBoS);
            ExcelUtil.exportExcle(request, response, workbook, fileName);
            return Result.success("导出成功");
        }
        return Result.success("未查询到数据");
    }

    @Override
    public List<SRevenueSettleLettersMerchantBo> summarySettleLettersMerchantInfo(SSettleLettersDetailQueryBO queryBo) {
        return this.getBaseMapper().summarySettleLettersMerchantInfo(queryBo);
    }

    @Override
    public List<SRevenueSettleLettersMerchantDetailBo> detailSettleLettersMerchantInfo(SSettleLettersDetailQueryBO queryBo) {
        return this.getBaseMapper().detailSettleLettersMerchantInfo(queryBo);
    }

    /**
     * nc取数
     * @param ncCloudReqVO
     * @return
     */
    @Override
    public PageInfo<NcCloudResVO> ncCloudGet(NcCloudReqVO ncCloudReqVO) {
        ncCloudReqVO.buildStart();
        if (CollectionUtils.isEmpty(ncCloudReqVO.getRevenueStatus())) {
            // 如果没有传入状态，则默认统计有效记录
            ncCloudReqVO.setRevenueStatus(Collections.singletonList(RevenueStatusEnum.NORMAL.getCode()));
        }
        //nc只查询云南腾云信息产业有限公司/云南腾小云旅行社有限公司 机构下的数据
        /*if(CollectionUtils.isEmpty(ncCloudReqVO.getOrgCodes())){
            //查询参数不传默认查询这两个机构下的数据
            ncCloudReqVO.setOrgCodes(orgCodes);
        }*/
        if(!StringUtils.isEmpty(ncCloudReqVO.getRevenueType())){
            List<String> revenueTypes=new ArrayList<>();
            if(RevenueTypeEnum.ALL.getRevenueType().equals(ncCloudReqVO.getRevenueType())){
                revenueTypes.add(RevenueTypeEnum.ALL.getRevenueType());
            }else{
                revenueTypes.add(RevenueTypeEnum.PART.getRevenueType());
                revenueTypes.add(RevenueTypeEnum.FIXED_SCALE.getRevenueType());
                revenueTypes.add(RevenueTypeEnum.FIXED_AMOUNT.getRevenueType());
            }
            ncCloudReqVO.setRevenueTypeList(revenueTypes);
        }

       // LocalDateTime startDate = LocalDateTime.parse(ncCloudReqVO.getStartDateTime(),DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
       // LocalDateTime endDate = LocalDateTime.parse(ncCloudReqVO.getEndDateTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        Integer count = this.getBaseMapper().getRevenueByOrgCount(ncCloudReqVO);
        List<NcCloudResVO> list = this.getBaseMapper().getRevenueByOrg(ncCloudReqVO);
        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(item -> {
                item.setCreateTime(ncCloudReqVO.getStartDateTime().substring(0,10));
                item.setRevenueType(item.getRevenueType());
                item.setRevenueTypeName(RevenueTypeEnum.getDesc(item.getRevenueType()));
                item.setDebitOrderCount(item.getOrderCount());
                item.setOrderSourceName(OrderSourceEnum.getDesc(item.getOrderSource()));
                item.setId(DateTimeUtil.format(LocalDateTime.now(), DateTimeUtil.yyyyMMdd)+idGenerateUtil.getUniqueIDByKey("NCCID","%09d",true, TimeUnit.DAYS,1L));//年月日+流水码
                item.setPriceWithTax(item.getSubOrderAmountTotal());
                item.setTotalCost(item.getProductCostTotal());
            });
        }
        return new PageInfo<NcCloudResVO>(list, new PageInfo.Pagination(ncCloudReqVO.getCurrentPage(), ncCloudReqVO.getPageSize(), count));
    }

    private BaseRevenueQueryBO queryDateHandle(BaseRevenueQueryVo revenueQueryVo){
        BaseRevenueQueryBO baseRevenueQueryBO = ObjectConvertUtil.convert(revenueQueryVo, BaseRevenueQueryBO.class).get();
        baseRevenueQueryBO.setStartDateTime(LocalDateTime.of(revenueQueryVo.getStartDate(), LocalTime.of(0, 0, 0)));
        baseRevenueQueryBO.setEndDateTime(LocalDateTime.of(revenueQueryVo.getEndDate(), LocalTime.of(23, 59, 59)));
        return baseRevenueQueryBO;
    }

    /**
     * 计算收入金额
     *
     * @param subOrder
     * @param merchantQueryBo
     * @return
     */
    private Integer getRevenueAmount(SubOrder subOrder, MerchantQueryBo merchantQueryBo) {
        RevenueTypeEnum revenueTypeEnum = RevenueTypeEnum.getRevenueTypeEnum(merchantQueryBo.getRevenueType());
        Integer revenueAmount = 0;
        switch (revenueTypeEnum) {
            case ALL:
                // 全额确认
                revenueAmount = subOrder.getSubOrderAmount();
                break;
            case PART:
                // 差额确认
                revenueAmount = subOrder.getSubOrderAmount() - subOrder.getProductCost();
                break;
            case FIXED_SCALE:
                // 固定比例
                revenueAmount = BigDecimal.valueOf(subOrder.getSubOrderAmount()).multiply(merchantQueryBo.getPlatformRevenueScale())
                        .divide(BigDecimal.valueOf(100), 10,BigDecimal.ROUND_DOWN).intValue();
                break;
            case FIXED_AMOUNT:
                // 固定金额
                revenueAmount = BigDecimal.valueOf(subOrder.getProductCount()).multiply(BigDecimal.valueOf(merchantQueryBo.getPlatformRevenueAmount())).intValue();
                break;
            default:
                // 实际上不会走到，但是code
                revenueAmount = 0;
                log.error("未知的收入确认类型:{}", revenueTypeEnum.getRevenueType());
        }
        return revenueAmount;
    }

    private MerchantQueryBo getMerchantRevenueType(List<MerchantQueryBo> merchantCods, String merchantCode) {
        List<MerchantQueryBo> merchantQueryBos = merchantCods.stream().filter(m -> m.getMerchantCode().equals(merchantCode)).collect(Collectors.toList());
        return CollectionUtils.isEmpty(merchantQueryBos) ? null : merchantQueryBos.get(0);
    }
}
